package com.lineage.server.model;

import com.lineage.config.Config;
import com.lineage.server.datatables.ItemTable;
import com.lineage.server.datatables.UBSpawnTable;
import com.lineage.server.datatables.UBTable;
import com.lineage.server.datatables.UbSupplies;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1MonsterInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.serverpackets.S_ServerMessage;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.L1Item;
import com.lineage.server.thread.GeneralThreadPool;
import com.lineage.server.utils.IntRange;
import com.lineage.server.utils.Random;
import com.lineage.server.utils.collections.Lists;
import com.lineage.server.world.World;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

public class L1UltimateBattle {
  private int _locX;
  
  private int _locY;
  
  private L1Location _location;
  
  private short _mapId;
  
  private int _locX1;
  
  private int _locY1;
  
  private int _locX2;
  
  private int _locY2;
  
  private int _ubId;
  
  private int _pattern;
  
  private boolean _isNowUb;
  
  private boolean _active;
  
  private int _minLevel;
  
  private int _maxLevel;
  
  private int _maxPlayer;
  
  private boolean _enterRoyal;
  
  private boolean _enterKnight;
  
  private boolean _enterMage;
  
  private boolean _enterElf;
  
  private boolean _enterDarkelf;
  
  private boolean _enterDragonKnight;
  
  private boolean _enterIllusionist;
  
  private boolean _enterMale;
  
  private boolean _enterFemale;
  
  private boolean _usePot;
  
  private int _hpr;
  
  private int _mpr;
  
  private String _ubName;
  
  private static int BEFORE_MINUTE = 5;
  
  private Set<Integer> _managers;
  
  private SortedSet<Integer> _ubTimes;
  
  private static final Logger _log = Logger.getLogger(L1UltimateBattle.class.getName());
  
  private final List<L1PcInstance> _members;
  
  private String[] _ubInfo;
  
  private void sendRoundMessage(int curRound) {
    int[] MSGID_ROUND_TABLE = { 893, 894, 895, 896 };
    sendMessage(MSGID_ROUND_TABLE[curRound - 1], "");
  }
  
  private void spawnSupplies(int curRound) {
    List<L1UbSupplie> sup = UbSupplies.getInstance().getUbSupplies(curRound);
    if (sup.size() != 0) {
      Iterator<L1UbSupplie> iterator = sup.iterator();
      while (iterator.hasNext()) {
        L1UbSupplie t = iterator.next();
        spawnGroundItem(t.getUbItemId(), t.getUbItemStackCont(), t.getUbItemCont());
      } 
    } 
  }
  
  private void removeRetiredMembers() {
    L1PcInstance[] temp = getMembersArray();
    L1PcInstance[] array;
    int length = (array = temp).length;
    int i = 0;
    while (i < length) {
      L1PcInstance element = array[i];
      if (element.getMapId() != this._mapId)
        removeMember(element); 
      i++;
    } 
  }
  
  private void sendMessage(int type, String msg) {
    L1PcInstance[] membersArray;
    int length = (membersArray = getMembersArray()).length;
    int i = 0;
    while (i < length) {
      L1PcInstance pc = membersArray[i];
      pc.sendPackets((ServerBasePacket)new S_ServerMessage(type, msg));
      i++;
    } 
  }
  
  private void spawnGroundItem(int itemId, int stackCount, int count) {
    L1Item temp = ItemTable.get().getTemplate(itemId);
    if (temp == null)
      return; 
    int i = 0;
    while (i < count) {
      L1Location loc = this._location.randomLocation((getLocX2() - getLocX1()) / 2, false);
      if (temp.isStackable()) {
        L1ItemInstance item = ItemTable.get().createItem(itemId);
        item.setEnchantLevel(0);
        item.setCount(stackCount);
        L1GroundInventory ground = World.get().getInventory(loc.getX(), loc.getY(), this._mapId);
        if (ground.checkAddItem(item, stackCount) == 0)
          ground.storeItem(item); 
      } else {
        L1ItemInstance item = null;
        int createCount = 0;
        while (createCount < stackCount) {
          item = ItemTable.get().createItem(itemId);
          item.setEnchantLevel(0);
          L1GroundInventory ground2 = World.get().getInventory(loc.getX(), loc.getY(), this._mapId);
          if (ground2.checkAddItem(item, stackCount) == 0)
            ground2.storeItem(item); 
          createCount++;
        } 
      } 
      i++;
    } 
  }
  
  private void clearColosseum() {
    Iterator<L1Object> iterator = World.get().getVisibleObjects(this._mapId).values().iterator();
    while (iterator.hasNext()) {
      Object obj = iterator.next();
      if (obj instanceof L1MonsterInstance) {
        L1MonsterInstance mob = (L1MonsterInstance)obj;
        if (mob.isDead())
          continue; 
        mob.setDead(true);
        mob.setStatus(8);
        mob.setCurrentHpDirect(0);
        mob.deleteMe();
        continue;
      } 
      if (!(obj instanceof L1Inventory))
        continue; 
      L1Inventory inventory = (L1Inventory)obj;
      inventory.clearItems();
    } 
  }
  
  public L1UltimateBattle() {
    this._managers = new HashSet<>();
    this._ubTimes = new TreeSet<>();
    this._members = Lists.newArrayList();
  }
  
  public void start() {
    int patternsMax = UBSpawnTable.getInstance().getMaxPattern(this._ubId);
    this._pattern = Random.nextInt(patternsMax) + 1;
    UbThread ub = new UbThread();
    GeneralThreadPool.get().execute(ub);
  }
  
  public void addMember(L1PcInstance pc) {
    if (!this._members.contains(pc))
      this._members.add(pc); 
  }
  
  public void removeMember(L1PcInstance pc) {
    this._members.remove(pc);
  }
  
  public void clearMembers() {
    this._members.clear();
  }
  
  public boolean isMember(L1PcInstance pc) {
    return this._members.contains(pc);
  }
  
  public L1PcInstance[] getMembersArray() {
    return this._members.<L1PcInstance>toArray(new L1PcInstance[this._members.size()]);
  }
  
  public int getMembersCount() {
    return this._members.size();
  }
  
  private void setNowUb(boolean i) {
    this._isNowUb = i;
  }
  
  public boolean isNowUb() {
    return this._isNowUb;
  }
  
  public int getUbId() {
    return this._ubId;
  }
  
  public void setUbId(int id) {
    this._ubId = id;
  }
  
  public short getMapId() {
    return this._mapId;
  }
  
  public void setMapId(short mapId) {
    this._mapId = mapId;
  }
  
  public int getMinLevel() {
    return this._minLevel;
  }
  
  public void setMinLevel(int level) {
    this._minLevel = level;
  }
  
  public int getMaxLevel() {
    return this._maxLevel;
  }
  
  public void setMaxLevel(int level) {
    this._maxLevel = level;
  }
  
  public int getMaxPlayer() {
    return this._maxPlayer;
  }
  
  public void setMaxPlayer(int count) {
    this._maxPlayer = count;
  }
  
  public void setEnterRoyal(boolean enterRoyal) {
    this._enterRoyal = enterRoyal;
  }
  
  public void setEnterKnight(boolean enterKnight) {
    this._enterKnight = enterKnight;
  }
  
  public void setEnterMage(boolean enterMage) {
    this._enterMage = enterMage;
  }
  
  public void setEnterElf(boolean enterElf) {
    this._enterElf = enterElf;
  }
  
  public void setEnterDarkelf(boolean enterDarkelf) {
    this._enterDarkelf = enterDarkelf;
  }
  
  public void setEnterDragonKnight(boolean enterDragonKnight) {
    this._enterDragonKnight = enterDragonKnight;
  }
  
  public void setEnterIllusionist(boolean enterIllusionist) {
    this._enterIllusionist = enterIllusionist;
  }
  
  public void setEnterMale(boolean enterMale) {
    this._enterMale = enterMale;
  }
  
  public void setEnterFemale(boolean enterFemale) {
    this._enterFemale = enterFemale;
  }
  
  public boolean canUsePot() {
    return this._usePot;
  }
  
  public void setUsePot(boolean usePot) {
    this._usePot = usePot;
  }
  
  public int getHpr() {
    return this._hpr;
  }
  
  public void setHpr(int hpr) {
    this._hpr = hpr;
  }
  
  public int getMpr() {
    return this._mpr;
  }
  
  public void setMpr(int mpr) {
    this._mpr = mpr;
  }
  
  public int getLocX1() {
    return this._locX1;
  }
  
  public void setLocX1(int locX1) {
    this._locX1 = locX1;
  }
  
  public int getLocY1() {
    return this._locY1;
  }
  
  public void setLocY1(int locY1) {
    this._locY1 = locY1;
  }
  
  public int getLocX2() {
    return this._locX2;
  }
  
  public void setLocX2(int locX2) {
    this._locX2 = locX2;
  }
  
  public int getLocY2() {
    return this._locY2;
  }
  
  public void setLocY2(int locY2) {
    this._locY2 = locY2;
  }
  
  public void setName(String name) {
    this._ubName = name;
  }
  
  public String getName() {
    return this._ubName;
  }
  
  public void resetLoc() {
    this._locX = (this._locX2 + this._locX1) / 2;
    this._locY = (this._locY2 + this._locY1) / 2;
    this._location = new L1Location(this._locX, this._locY, this._mapId);
  }
  
  public L1Location getLocation() {
    return this._location;
  }
  
  public void addManager(int npcId) {
    this._managers.add(Integer.valueOf(npcId));
  }
  
  public boolean containsManager(int npcId) {
    return this._managers.contains(Integer.valueOf(npcId));
  }
  
  public void addUbTime(int time) {
    this._ubTimes.add(Integer.valueOf(time));
  }
  
  public String getNextUbTime() {
    return intToTimeFormat(nextUbTime());
  }
  
  private int nextUbTime() {
    SimpleDateFormat sdf = new SimpleDateFormat("HHmm");
    int nowTime = Integer.valueOf(sdf.format(getRealTime().getTime())).intValue();
    SortedSet<Integer> tailSet = this._ubTimes.tailSet(Integer.valueOf(nowTime));
    if (tailSet.isEmpty())
      tailSet = this._ubTimes; 
    return ((Integer)tailSet.first()).intValue();
  }
  
  private static String intToTimeFormat(int n) {
    return String.valueOf(String.valueOf(n / 100)) + ":" + (n % 100 / 10) + (n % 10);
  }
  
  private static Calendar getRealTime() {
    TimeZone _tz = TimeZone.getTimeZone(Config.TIME_ZONE);
    Calendar cal = Calendar.getInstance(_tz);
    return cal;
  }
  
  public boolean checkUbTime() {
    SimpleDateFormat sdf = new SimpleDateFormat("HHmm");
    Calendar realTime = getRealTime();
    realTime.add(12, BEFORE_MINUTE);
    int nowTime = Integer.valueOf(sdf.format(realTime.getTime())).intValue();
    return this._ubTimes.contains(Integer.valueOf(nowTime));
  }
  
  private void setActive(boolean f) {
    this._active = f;
  }
  
  public boolean isActive() {
    return this._active;
  }
  
  public boolean canPcEnter(L1PcInstance pc) {
    _log.log(Level.FINE, "pcname=" + pc.getName() + " ubid=" + this._ubId + " minlvl=" + 
        this._minLevel + " maxlvl=" + this._maxLevel);
    return (IntRange.includes(pc.getLevel(), this._minLevel, this._maxLevel) && ((pc.isCrown() && this._enterRoyal) || (
      pc.isKnight() && this._enterKnight) || (pc.isWizard() && this._enterMage) || (
      pc.isElf() && this._enterElf) || (pc.isDarkelf() && this._enterDarkelf) || (
      pc.isDragonKnight() && this._enterDragonKnight) || (pc.isIllusionist() && this._enterIllusionist)));
  }
  
  public String[] makeUbInfoStrings() {
    if (this._ubInfo != null)
      return this._ubInfo; 
    String nextUbTime = String.valueOf(String.valueOf(getNextUbTime())) + " ";
    StringBuilder classesBuff = new StringBuilder();
    if (this._enterDarkelf)
      classesBuff.append("黑暗妖精 "); 
    if (this._enterMage)
      classesBuff.append("法师 "); 
    if (this._enterElf)
      classesBuff.append("妖精 "); 
    if (this._enterKnight)
      classesBuff.append("骑士 "); 
    if (this._enterRoyal)
      classesBuff.append("王族 "); 
    if (this._enterDragonKnight)
      classesBuff.append("龙骑士 "); 
    if (this._enterIllusionist)
      classesBuff.append("幻术师 "); 
    String classes = classesBuff.toString().trim();
    StringBuilder sexBuff = new StringBuilder();
    if (this._enterMale)
      sexBuff.append("男 "); 
    if (this._enterFemale)
      sexBuff.append("女 "); 
    String sex = sexBuff.toString().trim();
    String loLevel = String.valueOf(String.valueOf(String.valueOf(this._minLevel)) + " ");
    String hiLevel = String.valueOf(String.valueOf(String.valueOf(this._maxLevel)) + " ");
    String teleport = this._location.getMap().isEscapable() ? "可以" : "不可以";
    String res = this._location.getMap().isUseResurrection() ? "可以" : "不可以";
    String pot = "可以";
    String hpr = String.valueOf(this._hpr);
    String mpr = String.valueOf(this._mpr);
    String summon = this._location.getMap().isTakePets() ? "可以" : "不可以";
    String summon2 = this._location.getMap().isRecallPets() ? "可以" : "不可以";
    this._ubInfo = new String[] { 
        nextUbTime, classes, sex, loLevel, hiLevel, teleport, res, "可以", hpr, mpr, 
        summon, summon2 };
    return new String[12];
  }
  
  class UbThread implements Runnable {
    private void countDown() throws InterruptedException {
      int MSGID_COUNT = 4702;
      int MSGID_START = 4701;
      int loop = 0;
      while (loop < L1UltimateBattle.BEFORE_MINUTE * 60 - 10) {
        Thread.sleep(1000L);
        loop++;
      } 
      L1UltimateBattle.this.removeRetiredMembers();
      L1UltimateBattle.this.sendMessage(4702, "10");
      Thread.sleep(5000L);
      L1UltimateBattle.this.sendMessage(4702, "5");
      Thread.sleep(1000L);
      L1UltimateBattle.this.sendMessage(4702, "4");
      Thread.sleep(1000L);
      L1UltimateBattle.this.sendMessage(4702, "3");
      Thread.sleep(1000L);
      L1UltimateBattle.this.sendMessage(4702, "2");
      Thread.sleep(1000L);
      L1UltimateBattle.this.sendMessage(4702, "1");
      Thread.sleep(1000L);
      L1UltimateBattle.this.sendMessage(4701, "アルティメット バトル");
      L1UltimateBattle.this.removeRetiredMembers();
    }
    
    private void waitForNextRound(int curRound) throws InterruptedException {
      int[] WAIT_TIME_TABLE = { 6, 6, 2, 18 };
      int wait = WAIT_TIME_TABLE[curRound - 1];
      int i = 0;
      while (i < wait) {
        Thread.sleep(10000L);
        i++;
      } 
      L1UltimateBattle.this.removeRetiredMembers();
    }
    
    public void run() {
      try {
        L1UltimateBattle.this.setActive(true);
        countDown();
        L1UltimateBattle.this.setNowUb(true);
        int round = 1;
        while (round <= 4) {
          L1UltimateBattle.this.sendRoundMessage(round);
          L1UbPattern pattern = UBSpawnTable.getInstance().getPattern(L1UltimateBattle.this._ubId, 
              L1UltimateBattle.this._pattern);
          List<L1UbSpawn> spawnList = pattern.getSpawnList(round);
          Iterator<L1UbSpawn> iterator = spawnList.iterator();
          while (iterator.hasNext()) {
            L1UbSpawn spawn = iterator.next();
            if (L1UltimateBattle.this.getMembersCount() > 0)
              spawn.spawnAll(); 
            Thread.sleep((spawn.getSpawnDelay() * 1000));
          } 
          if (L1UltimateBattle.this.getMembersCount() > 0)
            L1UltimateBattle.this.spawnSupplies(round); 
          L1PcInstance[] membersArray;
          int length = (membersArray = L1UltimateBattle.this.getMembersArray()).length;
          int i = 0;
          while (i < length) {
            L1PcInstance pc = membersArray[i];
            UBTable.getInstance().writeUbScore(L1UltimateBattle.this.getUbId(), pc);
            i++;
          } 
          waitForNextRound(round);
          round++;
        } 
        L1PcInstance[] membersArray2;
        int length2 = (membersArray2 = L1UltimateBattle.this.getMembersArray()).length;
        int j = 0;
        while (j < length2) {
          L1PcInstance pc2 = membersArray2[j];
          int rndx = Random.nextInt(4);
          int rndy = Random.nextInt(4);
          int locx = 33503 + rndx;
          int locy = 32764 + rndy;
          short mapid = 4;
          L1Teleport.teleport(pc2, locx, locy, (short)4, 5, true);
          L1UltimateBattle.this.removeMember(pc2);
          j++;
        } 
        L1UltimateBattle.this.clearColosseum();
        L1UltimateBattle.this.setActive(false);
        L1UltimateBattle.this.setNowUb(false);
      } catch (Exception e) {
        L1UltimateBattle._log.log(Level.SEVERE, e.getLocalizedMessage(), e);
      } 
    }
  }
}
